package bb.lanxing.calc;

import com.github.mikephil.charting.utils.Utils;
import bb.lanxing.calc.data.SourcePoint;
import bb.lanxing.manager.RemoteSharedPreference;
import bb.lanxing.manager.SPConstant;
import bb.lanxing.model.database.Workout;
import bb.lanxing.util.DistanceUtil;
import bb.lanxing.util.Log;

public class PointChecker {
    final private static String TAG = "PointChecker";
    private static final float INVALID_ACCURACY = 200.0f;
    private static final int INVALID_CHECK_COUNT = 30;
    private static final int INVALID_CYCLING_SPEED = 30;//not too big, used to drop GPS location jumping
    private static final int INVALID_DEFAULT_SPEED = 500;
    private static final int INVALID_DIFFERENCE_SPEED = 10;
    private static final int INVALID_RUNNING_SPEED = 25;
    private static final int INVALID_WALKING_SPEED = 20;
    private static final int LOST_GPS_INTERVAL = 10000;
    private SourcePoint lastValidPoint;
    private long lastValidTime = 0;
    private int checkCount = 0;

    public boolean isValid(SourcePoint sourcePoint) {
        boolean speedValid = isSpeedValid(sourcePoint);
        boolean accuracyValid = isAccuracyValid(sourcePoint);
        boolean trainingValid = isTrainingValid(sourcePoint);
        boolean indoorbikeValid = isIndoorbikeValid(sourcePoint);
        boolean crosstrainerValid = isCrosstrainerValid(sourcePoint);
        Log.d(TAG, "isValid: speedValid=" + speedValid + ", accuracyValid=" + accuracyValid + ", trainingValid=" + trainingValid);
        if ((speedValid && accuracyValid) || trainingValid || indoorbikeValid||crosstrainerValid) {
            return true;
        } else {
            return false;
        }
    }

    private boolean isSpeedValid(SourcePoint sourcePoint) {
        if (lastValidPoint == null) {
            if (sourcePoint.getSpeed() > Utils.DOUBLE_EPSILON) {
                lastValidPoint = sourcePoint;
                lastValidTime = sourcePoint.getTimestamp();
            }
            return false;
        }
        long timestamp = sourcePoint.getTimestamp();
        long vTimeInterval = timestamp - lastValidTime;
        double vSpeed = (DistanceUtil.get(lastValidPoint, sourcePoint) * 1000.0d) / vTimeInterval;//speed unit: m/s
        Log.d(TAG, "isSpeedValid: vSpeed=" + vSpeed + ", checkCount=" + checkCount + ", vTimeInterval=" + vTimeInterval);

        //Detected invalid data points for up to 30(INVALID_CHECK_COUNT)
        if (vSpeed > getMaxInvalidSpeed()
                || (vTimeInterval > LOST_GPS_INTERVAL && sourcePoint.getSpeed() == Utils.DOUBLE_EPSILON)
                || (vSpeed > 0.0f && Math.abs(vSpeed - sourcePoint.getSpeed()) > 10.0d)) {
            checkCount++;
            Log.d(TAG, "isSpeedValid: checkCount=" + checkCount);
            if (checkCount <= INVALID_CHECK_COUNT) {
                return false;
            }
        }

        lastValidPoint = sourcePoint;
        lastValidTime = timestamp;
        checkCount = 0;
        return true;
    }

    private int getMaxInvalidSpeed() {
        int vSportType = RemoteSharedPreference.getInstance().getInt(SPConstant.KEY_SPORT_TYPE, Workout.TYPE_CYCLING);

        if (vSportType == Workout.TYPE_WALKING) {
            return INVALID_WALKING_SPEED;
        } else if (vSportType == Workout.TYPE_RUNNING) {
            return INVALID_RUNNING_SPEED;
        } else if (vSportType == Workout.TYPE_CYCLING) {
            return INVALID_CYCLING_SPEED;
        } else {
            return INVALID_DEFAULT_SPEED;
        }
    }

    private boolean isAccuracyValid(SourcePoint sourcePoint) {
        return sourcePoint.hasGps() && sourcePoint.getGpsPoint().getAccuracy() <= INVALID_ACCURACY;
    }

    private boolean isTrainingValid(SourcePoint sourcePoint) {
        int vSportType = RemoteSharedPreference.getInstance().getInt(SPConstant.KEY_SPORT_TYPE, Workout.TYPE_CYCLING);
        return  vSportType == Workout.TYPE_TRAINING && sourcePoint.hasCadence();
    }
    private boolean isIndoorbikeValid(SourcePoint sourcePoint) {
        int vSportType = RemoteSharedPreference.getInstance().getInt(SPConstant.KEY_SPORT_TYPE, Workout.TYPE_INDOOR_BIKE);
        return  vSportType == Workout.TYPE_INDOOR_BIKE && sourcePoint.hasCadence();
    }
    private boolean isBiketrainerValid(SourcePoint sourcePoint) {
        int vSportType = RemoteSharedPreference.getInstance().getInt(SPConstant.KEY_SPORT_TYPE, Workout.TYPE_BIKE_TRAINER);
        return  vSportType == Workout.TYPE_BIKE_TRAINER && sourcePoint.hasCadence();
    }
    private boolean isRowerValid(SourcePoint sourcePoint) {
        int vSportType = RemoteSharedPreference.getInstance().getInt(SPConstant.KEY_SPORT_TYPE, Workout.TYPE_ROWER);
        return  vSportType == Workout.TYPE_ROWER && sourcePoint.hasCadence();
    }

    private boolean isCrosstrainerValid(SourcePoint sourcePoint) {
        int vSportType = RemoteSharedPreference.getInstance().getInt(SPConstant.KEY_SPORT_TYPE, Workout.TYPE_CROSS_TRAINER);
        return  vSportType == Workout.TYPE_CROSS_TRAINER && sourcePoint.hasCadence();
    }
    public void release() {
        lastValidPoint = null;
        lastValidTime = 0L;
        checkCount = 0;
    }
}
